// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Bars.cs" company="">
//   
// </copyright>
// <summary>
//   The bars.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
 
namespace Systemathics.FrameWork
{
    [Serializable]
    public sealed class Bars : IDisposable
    {
        public Instrument i                     { get; private set; }
        public int DefaultBarSize               { get; private set; }
        public BarType BarType                  { get; private set; }
        public event EventHandler<Bar> OnBar;

        private readonly TimeSpan BarSpan;
        private delegate void MakeBarDelegate();
        private readonly MakeBarDelegate TickOrVolumeDelegate;
        private readonly MakeBarDelegate TimeDelegate;
        private DateTime BeginTime;
        private bool FirstBar;
        private Trade LastQuote;
        private TradeSeries TradeSerie;
        private long Volume;

        public Bars(Instrument instrument, BarType barType, int value)
        {
            DefaultBarSize = value;
            BarType = barType;
            FirstBar = true;

            if (DefaultBarSize > 0)
            {
                i = instrument;
                TradeSerie = new TradeSeries(i.StaticData.Name);
                TradeSerie.EmitSeriesError += TradeSerieEmitSeriesError;

                if (i.StaticData.Classe == AssetClass.Forex && i.StaticData.Type == InstrumentType.Cash)
                    i.OnBlotter += OnBlotter;
                else
                    i.OnTrade += OnTrade;

                switch (BarType)
                {
                    case BarType.Seconds:
                        BarSpan = new TimeSpan(0, 0, 0, DefaultBarSize);
                        TimeDelegate = MakeTimeBar;
                        break;
                    case BarType.Ticks:
                        TickOrVolumeDelegate = MakeTickBar;
                        break;
                    case BarType.Volume:
                        Volume = 0;
                        TickOrVolumeDelegate = MakeVolumeBar;
                        break;
                    default:
                        break;
                }
            }
        }

        private static void TradeSerieEmitSeriesError(object sender, FireMessageEventArgs e)
        {
        }
        private void OnBlotter(object sender, Blotter e)
        {
            if (e.TickInfo == TickInfo.Bid_1 || e.TickInfo == TickInfo.Ask_1 || e.TickInfo == TickInfo.BidSize_1 || e.TickInfo == TickInfo.AskSize_1)
            {
                // CanadaDry !!!
                LastQuote = new Trade(e[QuoteLevel.One].Id, e[QuoteLevel.One].Time, e[QuoteLevel.One].Mid, Math.Min(e[QuoteLevel.One].BidSize, e[QuoteLevel.One].AskSize)); 
                Volume += LastQuote.Size;

                if (TimeDelegate != null)
                    TimeDelegate.Invoke();
                else if (TickOrVolumeDelegate != null)
                    TickOrVolumeDelegate.Invoke();   
            }
        }
        private void OnTrade(object sender, Trade e)
        {
            Volume += e.Size;

            if (TimeDelegate != null)
                TimeDelegate.Invoke();
            else if (TickOrVolumeDelegate != null)
                TickOrVolumeDelegate.Invoke();
        }

        private void MakeTimeBar()
        {
            try
            {
                lock (this)
                {
                    var lq = LastQuote.Clone();
                    if (FirstBar)
                    {
                        BeginTime = LastQuote.Time;
                        FirstBar = false;
                    }
                    else if (LastQuote.Time - BeginTime >= BarSpan)
                    {
                        var t = LastQuote.Time - BeginTime;
                        new RemotingLogClient().Trace(new FireMessageEventArgs(t.TotalSeconds.ToString(),Time.Now.TimeOfDay));

                        var b = new Bar(TradeSerie.First().Time, TradeSerie.Last().Time, TradeSerie.First().Price, TradeSerie.High(), TradeSerie.Low(), TradeSerie.Last().Price, DefaultBarSize, Volume, 0) { Id = i.Id };
                        TradeSerie.Clear();
                        FirstBar = true;
                        Volume = 0;
                        if (OnBar != null)
                            OnBar(this, b);
                    }
                    else
                    {
                        TradeSerie.Add(LastQuote);
                    }
                }
            }
            catch (Exception e)
            {
            }
        }
        private void MakeTickBar()
        {
            if (TradeSerie.Count >= DefaultBarSize)
            {
                var b = new Bar(TradeSerie.First().Time, TradeSerie.Last().Time, TradeSerie.First().Price, TradeSerie.High(), TradeSerie.Low(), TradeSerie.Last().Price, DefaultBarSize, Volume, 0){Id = i.Id};
                TradeSerie.Clear();
                Volume = 0;
                if (OnBar != null)
                    OnBar(this, b);
            }
            else
            {
                TradeSerie.Add(LastQuote);
            }
        }
        private void MakeVolumeBar()
        {
            if (Volume >= DefaultBarSize)
            {
                var b = new Bar(TradeSerie.First().Time, TradeSerie.Last().Time, TradeSerie.First().Price, TradeSerie.High(), TradeSerie.Low(), TradeSerie.Last().Price, DefaultBarSize, Volume, 0){Id = i.Id};
                TradeSerie.Clear();
                Volume = 0;
                if (OnBar != null)
                    OnBar(this, b);
            }
            else
            {
                TradeSerie.Add(LastQuote);
            }
        }

        #region IDisposable Members

        void IDisposable.Dispose()
        {
            if (i.StaticData.Classe == AssetClass.Forex && i.StaticData.Type == InstrumentType.Cash)
                i.OnBlotter -= OnBlotter;
            else
                i.OnTrade -= OnTrade;

        }

        #endregion
    }
}